package fun.xinnix.concurrent;

import cn.hutool.log.StaticLog;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantTest {
    static class NumberWrapper {
        private int value = 1;
    }

    private static final ThreadPoolExecutor THREAD_POOL = ThreadPoolDemo.getThreadPool();

    public static void main(String[] args) {
        conditionTest2();
    }

    public static void conditionTest2() {
        Lock lock = new ReentrantLock();
        // 一个condition只能有一对await，signal，即，一个condition的signal方法只能唤醒一个await
        // 一个condition如果有多个线程await，需要全部唤醒，可以使用signalAll()方法
        Condition conditionA = lock.newCondition();
        Condition conditionC = lock.newCondition();
        THREAD_POOL.execute(() -> {
            lock.lock();
            StaticLog.info("A get lock");
            try {
                StaticLog.info("A await");
                conditionA.await();
                StaticLog.info("A complete");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
                StaticLog.info("A release lock");
            }
        });
        THREAD_POOL.execute(() -> {
            lock.lock();
            StaticLog.info("C get lock");
            try {
                StaticLog.info("C await");
                conditionC.await();
                StaticLog.info("C complete");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
                StaticLog.info("C release lock");
            }
        });
        THREAD_POOL.execute(() -> {
            lock.lock();
            StaticLog.info("B get lock");
            try {
                conditionA.signal();
                conditionC.signal();
                StaticLog.info("B complete");
            } finally {
                lock.unlock();
                StaticLog.info("B release lock");
            }
        });
        THREAD_POOL.shutdown();
    }

    public static void printLog(final String name, Lock lock){

    }

    public static void conditionTest1() {
        Lock lock = new ReentrantLock();
        Condition reachThree = lock.newCondition();
        Condition reachSix = lock.newCondition();
        NumberWrapper number = new NumberWrapper();
        THREAD_POOL.execute(() -> {
            lock.lock();
            StaticLog.info("A1 get lock");
            try {
                while (number.value <= 3) {
                    StaticLog.info("A number:{}", number.value);
                    number.value++;
                }
                StaticLog.info("A1 reachThree.signal");
                reachThree.signal();
            } finally {
                lock.unlock();
                StaticLog.info("A1 release lock");
            }

            StaticLog.info("A2 get lock");
            lock.lock();
            try {
                if (number.value > 3 && number.value <= 9) {
                    StaticLog.info("A2 reachSix.await");
                    reachSix.await();
                }
                while (number.value > 3 && number.value <= 9) {
                    StaticLog.info("A number:{}", number.value);
                    number.value++;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
                StaticLog.info("A2 release lock");
            }
        });

        THREAD_POOL.execute(() -> {
            lock.lock();
            StaticLog.info("B1 get lock");
            try {
                if (number.value <= 3) {
                    StaticLog.info("B1 reachThree await");
                    reachThree.await();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
                StaticLog.info("B1 release lock");
            }

            StaticLog.info("B2 get lock");
            lock.lock();
            try {
                while (number.value <= 6) {
                    StaticLog.info("B number:{}", number.value);
                    number.value++;
                }
                StaticLog.info("B2 reachSix.signal");
                reachSix.signal();
            } finally {
                lock.unlock();
                StaticLog.info("B2 release lock");
            }
        });

        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        THREAD_POOL.shutdown();
    }
}
